package session

import (
	"context"
	"net/http"

	"gitee.com/mkwchecking/sr-core/yal/yconv"
	"gitee.com/mkwchecking/sr-core/yerr"
)

var _instance *SessionManager

func NewSessionManager(ctx context.Context, cfg *SessionConfig) (*SessionManager, error) {
	if _instance != nil {
		return _instance, nil
	}

	stor, err := NewStore(ctx, *cfg)
	if err != nil {
		return nil, err
	}

	_instance = &SessionManager{
		stor: stor,
		cfg:  *cfg,
	}

	return _instance, nil
}

type SessionManager struct {
	stor Storage
	cfg  SessionConfig
}

func (m *SessionManager) GetStore() Storage {
	return m.stor
}

func (m *SessionManager) GetSessionInfo(ctx context.Context, req *http.Request) (map[string]any, error) {
	id, err := m.GetSessionId(req)
	if err != nil {
		return nil, err
	}

	return m.stor.GetSession(ctx, id, 0)
}

func (m *SessionManager) GetSessionObj(ctx context.Context, req *http.Request, obj interface{}) error {
	sessionInf, err := m.GetSessionInfo(ctx, req)
	if err != nil {
		return err
	}

	return yconv.AnyToObj(sessionInf, obj)
}

func (m *SessionManager) DefaultInfo(ctx context.Context, req *http.Request) (*Info, error) {
	info := NewInfo()
	return info, m.GetSessionObj(ctx, req, info)
}

func (m *SessionManager) GetSessionId(req *http.Request) (string, error) {
	for _, f := range m.cfg.KeyFrom {
		switch f {
		case "query":
			if id := m.getSessionIdFromQuery(req); id != "" {
				return id, nil
			}
		case "cookie":
			if id := m.getSessionIdFromCookie(req); id != "" {
				return id, nil
			}
		case "header":
			if id := m.getSessionIdFromHeader(req); id != "" {
				return id, nil
			}

		}
	}
	return "", yerr.ErrDataNotfound.Error()

}

func (m *SessionManager) getSessionIdFromQuery(req *http.Request) string {
	return req.URL.Query().Get(m.cfg.Key)
}

func (m *SessionManager) getSessionIdFromCookie(req *http.Request) string {
	cookie, err := req.Cookie(m.cfg.Key)
	if err != nil {
		return ""
	}
	return cookie.Value
}

func (m *SessionManager) getSessionIdFromHeader(req *http.Request) string {
	return req.Header.Get(m.cfg.Key)
}
